home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 2000-1 drscholl@users.sourceforge.net
- This is free software distributed under the terms of the
- GNU Public License. See the file COPYING for details.
-
- $Id: metaserver.c,v 1.18 2001/02/15 08:39:45 drscholl Exp $ */
-
- /* a simple napster metaserver. redirects clients to a specific set of
- servers */
-
- /* Modified 29/05/01 : Added include "confdefs.h" since we are not using the
- for Amiga port : CONFIGURE script
-
- Added define for htons(), which is not defined in the
- Amiga GCC 2.7.0 includes
-
- Added value for __auto_socket_vers to permit automatic
- opening/closing of bsdsocket.library by socket.o
-
- Added include "extrasocket.h" with inlines for a few
- bsdsocket.library functions not emulated by ixemul
-
- Removed openlog() and closelog() calls, not needed by
- bsdsocket.library
-
- 30/05/01 : Added varargs stub syslog() outside extrasocket.h. I
- intended to have this in extrasocket.h itself, but in
- another file there is a conflicting declaration of
- syslog().
- */
-
- #include "confdefs.h"
-
- #define htons(x) (x)
-
- unsigned long __auto_socket_vers = 4;
-
- #include <unistd.h>
- #include <signal.h>
- #include <stdlib.h>
- #include <string.h>
- #include <stdio.h>
- #include <limits.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #if HAVE_POLL
- #include <sys/poll.h>
- #endif /* HAVE_POLL */
- #include <syslog.h>
-
- #include "extrasocket.h"
-
- /* varargs stub for syslog() */
-
- void syslog(int level, const char * format, ...)
- {
- vsyslog(level, format, (&format) + 1);
- }
-
- #ifdef __CYGWIN__
- extern char *optarg;
- extern int optind;
- #endif
-
- char metafile[_POSIX_PATH_MAX];
- char *hosts[64];
- int numhosts = 0;
- volatile int sig_meta = 0;
-
- #ifndef HAVE_SOCKLEN_T
- typedef unsigned int socklen_t;
- #endif
-
- static void
- handler (int sig)
- {
- if (sig == SIGHUP)
- sig_meta++;
- }
-
- static void
- usage (void)
- {
- puts
- ("usage: metaserver [ -fsv ] [ -c CONFIG ] [ -l IP ] [ -p <port> ] [ host:port ... ]");
- puts (" -c CONFIG use list of servers in file CONFIG");
- puts (" -f run the metaserver in the background");
- puts (" -v display version number and exit");
- puts (" -l IP listen only on interface for IP");
- puts (" -p <port> listen for connection on <port> (default is 8875)");
- puts (" -s disable syslog messages");
- puts ("\n if no arguments are given, defaults to 127.0.0.1:8888");
- exit (1);
- }
-
- static void
- read_metafile (char *filename)
- {
- char buffer[90];
-
- FILE *fp;
-
- fp = fopen (filename, "r");
- if (!fp)
- return;
- while (fgets (buffer, sizeof (buffer) - 1, fp))
- {
- buffer[strlen (buffer) - 1] = 0;
- if (strlen (buffer) > 0 && buffer[0] != '#')
- hosts[numhosts++] = strdup (buffer);
- }
- fclose (fp);
- }
-
- int
- main (int argc, char **argv)
- {
- struct sockaddr_in sin;
- int i, s, f, port = 8875;
- int location = 0;
- int sys_log = 1;
- int background = 0;
-
- #if HAVE_POLL
- struct pollfd ufd;
- #else
- fd_set set;
- #endif /* HAVE_POLL */
- socklen_t sinsize;
- struct sigaction sa;
- unsigned int iface = INADDR_ANY;
-
- metafile[0] = 0;
-
- while ((i = getopt (argc, argv, "hfl:vp:c:s")) != EOF)
- {
- switch (i)
- {
- case 'l':
- iface = inet_addr (optarg);
- break;
- case 'p':
- port = atoi (optarg);
- break;
- case 'c':
- strcpy (metafile, optarg);
- break;
- case 'f':
- background ^= 1;
- break;
- case 's':
- sys_log ^= 1;
- break;
- case 'v':
- printf ("%s metaserver version %s\n", PACKAGE, VERSION);
- exit (1);
- default:
- usage ();
- }
- }
-
- /* read in the host list */
- if (!metafile[0])
- {
- if (!argv[optind])
- hosts[numhosts++] = strdup ("127.0.0.1:8888"); /* use default host */
- else
- {
- while (argv[optind])
- {
- hosts[numhosts++] = strdup (argv[optind]);
- optind++;
- }
- }
- }
- else
- read_metafile (metafile);
-
- /* set some signal handlers so we can shut down gracefully */
- memset (&sa, 0, sizeof (sa));
- sa.sa_handler = handler;
- sigaction (SIGINT, &sa, 0);
- sigaction (SIGTERM, &sa, 0);
-
- #ifndef __CYGWIN__
- sa.sa_flags = SA_RESTART;
- #endif
- sigaction (SIGHUP, &sa, NULL);
-
- memset (&sin, 0, sizeof (sin));
- sin.sin_port = htons (port);
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = iface;
-
- s = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (s < 0)
- {
- perror ("socket");
- exit (1);
- }
- if (bind (s, (struct sockaddr *) &sin, sizeof (sin)) < 0)
- {
- perror ("bind");
- exit (1);
- }
- if (listen (s, 50) < 0)
- {
- perror ("listen");
- exit (1);
- }
-
- if (background && fork ())
- _exit (0);
-
- /* if (sys_log)
- openlog ("metaserver", LOG_PID, LOG_LOCAL6); */
-
- location = 0;
- #if HAVE_POLL
- memset (&ufd, 0, sizeof (ufd));
- ufd.fd = s;
- ufd.events = POLLIN | POLLHUP;
- #endif /* HAVE_POLL */
- for (;;)
- {
- #if HAVE_POLL
- i = poll (&ufd, 1, -1);
- #else
- FD_ZERO (&set);
- FD_SET (s, &set);
- i = select (s + 1, &set, 0, 0, 0);
- #endif /* HAVE_POLL */
- if (i == -1)
- {
- /* re-read configuration files */
- if (sig_meta)
- {
- for (i = 0; i < numhosts; i++)
- free (hosts[i]);
- numhosts = 0;
- location = 0;
- sig_meta = 0;
- read_metafile (metafile);
- continue;
- }
- perror (
- #if HAVE_POLL
- "poll"
- #else
- "select"
- #endif
- );
- break;
- }
-
- sinsize = sizeof (sin);
- f = accept (s, (struct sockaddr *) &sin, &sinsize);
- if (f < 0)
- {
- perror ("accept");
- break;
- }
- write (f, hosts[location], strlen (hosts[location]));
- write (f, "\n", 1);
- if (sys_log)
- syslog (LOG_ERR, "Redirecting %s to %s", inet_ntoa (sin.sin_addr),
- hosts[location]);
- location = (location + 1) % numhosts;
- close (f);
- }
- close (s);
- /* closelog (); */
- exit (0);
- }
-